package com.xiaomi.task;

import com.xiaomi.entity.Rule;
import com.xiaomi.entity.Signal;
import com.xiaomi.service.RuleService;
import com.xiaomi.service.SignalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
public class DataConsistencyCheckTask {

    @Autowired
    private RuleService ruleService;

    @Autowired
    private SignalService signalService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 每小时执行一次数据一致性检查
     */
    @Scheduled(cron = "0 0 * * * ?") // 每小时整点执行
    public void checkRuleConsistency() {
        log.info("开始执行规则数据一致性检查任务 - {}", LocalDateTime.now());

        // 获取所有电池类型
        List<String> batteryTypes = ruleService.getAllBatteryTypes();

        for (String batteryType : batteryTypes) {
            // 获取数据库中的规则
            List<Rule> dbRules = ruleService.getRulesByBatteryTypeFromDB(batteryType);

            // 构建Redis键前缀
            String redisKeyPrefix = "rule:batteryType:" + batteryType;

            // 获取Redis中的所有规则键
            Set<String> redisKeys = redisTemplate.keys(redisKeyPrefix + "*");

            // 转换为Set便于比较
            Set<String> dbRuleKeys = dbRules.stream()
                    .map(rule -> redisKeyPrefix + ":ruleCode:" + rule.getRuleCode())
                    .collect(Collectors.toSet());

            // 检查缺失的规则
            Set<String> missingInRedis = new HashSet<>(dbRuleKeys);
            missingInRedis.removeAll(redisKeys);

            if (!missingInRedis.isEmpty()) {
                log.warn("发现Redis中缺失的规则: {}", missingInRedis);
                // 补充缺失的规则
                for (Rule rule : dbRules) {
                    if (missingInRedis.contains(redisKeyPrefix + ":ruleCode:" + rule.getRuleCode())) {
                        redisTemplate.opsForValue().set(
                                redisKeyPrefix + ":ruleCode:" + rule.getRuleCode(),
                                rule,
                                1, TimeUnit.HOURS);
                    }
                }
            }

            // 检查多余的规则
            Set<String> extraInRedis = new HashSet<>(redisKeys);
            extraInRedis.removeAll(dbRuleKeys);

            if (!extraInRedis.isEmpty()) {
                log.warn("发现Redis中多余的规则: {}", extraInRedis);
                // 可以选择删除多余的规则或记录日志
                // redisTemplate.delete(extraInRedis);
            }

            // 检查规则内容是否一致
            for (Rule dbRule : dbRules) {
                String redisKey = redisKeyPrefix + ":ruleCode:" + dbRule.getRuleCode();
                Rule redisRule = (Rule) redisTemplate.opsForValue().get(redisKey);

                if (redisRule == null) {
                    continue; // 已经在缺失检查中处理
                }

                if (!dbRule.equals(redisRule)) {
                    log.warn("发现规则不一致: 数据库规则ID={}, Redis规则ID={}",
                            dbRule.getRuleId(), ((Rule)redisTemplate.opsForValue().get(redisKey)).getRuleId());
                    // 更新Redis中的规则
                    redisTemplate.opsForValue().set(redisKey, dbRule, 1, TimeUnit.HOURS);
                }
            }
        }

        log.info("规则数据一致性检查任务完成 - {}", LocalDateTime.now());
    }

    /**
     * 每30分钟执行一次信号数据一致性检查
     */
    @Scheduled(cron = "0 */30 * * * ?") // 每30分钟执行一次
    public void checkSignalConsistency() {
        log.info("开始执行信号数据一致性检查任务 - {}", LocalDateTime.now());

        // 获取所有车架编号
        List<Integer> frameNumbers = signalService.getAllFrameNumbers();

        for (Integer frameNumber : frameNumbers) {
            // 获取数据库中的最新信号
            Signal dbSignal = signalService.getLatestSignalByFrameNumber(frameNumber);

            if (dbSignal == null) {
                // 如果没有信号数据，删除Redis中的相关键
                String maxVoltageKey = "car:" + frameNumber + ":max_voltage";
                String minVoltageKey = "car:" + frameNumber + ":min_voltage";
                String maxCurrentKey = "car:" + frameNumber + ":max_current";
                String minCurrentKey = "car:" + frameNumber + ":min_current";

                redisTemplate.delete(maxVoltageKey);
                redisTemplate.delete(minVoltageKey);
                redisTemplate.delete(maxCurrentKey);
                redisTemplate.delete(minCurrentKey);

                log.info("车架编号{}没有信号数据，已清理Redis缓存", frameNumber);
                continue;
            }

            // 检查并更新最大电压
            String maxVoltageKey = "car:" + frameNumber + ":max_voltage";
            Double dbMaxVoltage = dbSignal.getVoltage();
            Double redisMaxVoltage = (Double) redisTemplate.opsForValue().get(maxVoltageKey);

            if (redisMaxVoltage == null || dbMaxVoltage > redisMaxVoltage) {
                redisTemplate.opsForValue().set(maxVoltageKey, dbMaxVoltage);
                log.debug("更新车架编号{}的最大电压: {}", frameNumber, dbMaxVoltage);
            }

            // 检查并更新最小电压
            String minVoltageKey = "car:" + frameNumber + ":min_voltage";
            Double dbMinVoltage = dbSignal.getVoltage();
            Double redisMinVoltage = (Double) redisTemplate.opsForValue().get(minVoltageKey);

            if (redisMinVoltage == null || dbMinVoltage < redisMinVoltage) {
                redisTemplate.opsForValue().set(minVoltageKey, dbMinVoltage);
                log.debug("更新车架编号{}的最小电压: {}", frameNumber, dbMinVoltage);
            }

            // 检查并更新最大电流
            String maxCurrentKey = "car:" + frameNumber + ":max_current";
            Double dbMaxCurrent = dbSignal.getCurrent();
            Double redisMaxCurrent = (Double) redisTemplate.opsForValue().get(maxCurrentKey);

            if (redisMaxCurrent == null || dbMaxCurrent > redisMaxCurrent) {
                redisTemplate.opsForValue().set(maxCurrentKey, dbMaxCurrent);
                log.debug("更新车架编号{}的最大电流: {}", frameNumber, dbMaxCurrent);
            }

            // 检查并更新最小电流
            String minCurrentKey = "car:" + frameNumber + ":min_current";
            Double dbMinCurrent = dbSignal.getCurrent();
            Double redisMinCurrent = (Double) redisTemplate.opsForValue().get(minCurrentKey);

            if (redisMinCurrent == null || dbMinCurrent < redisMinCurrent) {
                redisTemplate.opsForValue().set(minCurrentKey, dbMinCurrent);
                log.debug("更新车架编号{}的最小电流: {}", frameNumber, dbMinCurrent);
            }
        }

        log.info("信号数据一致性检查任务完成 - {}", LocalDateTime.now());
    }
}